package com.niiwoo.civet.trade.listener;

import com.alibaba.fastjson.JSONException;
import com.niiwoo.tripod.provider.exception.BizException;
import com.rabbitmq.client.Channel;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * @author lichuanzhi
 * @date 2018/01/26
 */

@Slf4j
@Setter
abstract class BaseListener {
    private UncheckedRunable runnable;

    void receive(Message message, Channel channel){
        FeedBackActionEnum action = FeedBackActionEnum.ACCEPT;
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            runnable.run();
        }
        catch (JSONException | BizException | IllegalArgumentException | NullPointerException e ) {
            log.error("handle message occur can't retry exception.",e);
            action = FeedBackActionEnum.REJECT;
        }catch (Exception e) {
            log.error("handle message occur may retry exception.",e);
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e1) {
                log.error("handle message occur InterruptedException.",e);
            }
            action = FeedBackActionEnum.RETRY;
        }
        finally {
            if (action == FeedBackActionEnum.ACCEPT) {
                try {
                    channel.basicAck(deliveryTag,false);
                } catch (IOException e) {
                    log.error("basicAck ack occur exception, the reason is : {}", e);
                }
            } else if (action == FeedBackActionEnum.RETRY) {
                try {
                    channel.basicNack(deliveryTag, false, true);
                } catch (IOException e) {
                    log.error("basicNack ack occur exception, the reason is : {}", e);
                }
            } else {
                try {
                    channel.basicNack(deliveryTag, false, false);
                } catch (IOException e) {
                    log.error("basicReject ack occur exception, the reason is : {}", e);
                }
            }
        }
    }

    BaseListener handler(UncheckedRunable runnable) {
        this.setRunnable(runnable);
        return this;
    }

    @FunctionalInterface
    interface UncheckedRunable {

        /**
         * 消息处理逻辑
         * @throws Exception 抛出受检查异常的run方法，已达到消息处理逻辑代码不用处理检查异常的目的
         */
        void run() throws Exception;
    }

    private enum FeedBackActionEnum {
        /**
         * 处理成功
         */
        ACCEPT,

        /**
         * 可以重试的错误
         */
        RETRY,

        /**
         * 无需重试的错误
         */
        REJECT
    }



}
